﻿using System;
using System.IO;
using System.IO.Compression;
using System.Threading;
using System.Windows.Interop;

using Microsoft.DirectX.DirectSound;
using Talk.Net.Library;

namespace Talk.Net
{
	class CaptureDevice
	{
		private CaptureBufferDescription _bufferDescription;
		private CaptureBuffer _buffer;
		private Capture capture;
		private int _bufferSize;
		private AutoResetEvent BufferNotification;

		private byte[] RecordBuffer;
		private byte[] DoubleBuffer;
		private MemoryStream RecordStream;
		private DeflateStream CompressedStream;
		private int CapturePosition, ReadPosition;
		private int HalfBufferSize;

		private bool Continue;

		public delegate void ContentNotifierDelegate(byte[] content);
		public event ContentNotifierDelegate ContentNotification;

		public CaptureDevice()
		{
			Continue = true;

			HalfBufferSize = FormatManager.BytesPerSecond / 2;

			RecordBuffer = new byte[HalfBufferSize];
			DoubleBuffer = new byte[HalfBufferSize];
			RecordStream = new MemoryStream(RecordBuffer,0,HalfBufferSize,true,true);
			CompressedStream = new DeflateStream(RecordStream, CompressionMode.Compress);
		}

		public void Shutdown()
		{
			Continue = false;
			if (BufferNotification != null)
			{
				BufferNotification.Set();
			}
		}

		public void Capture()
		{
			BufferNotification = new AutoResetEvent(false);

			ThreadStart manageBuffer = new ThreadStart(ManageBuffer);
			Thread manageBufferThread = new Thread(manageBuffer);
			manageBufferThread.Start();
			Record();
		}

		private void Record()
		{
			CaptureDevicesCollection captureDeviceCollection = new CaptureDevicesCollection();

			//Check that there is a capture device
			if (captureDeviceCollection.Count == 0)
				throw new Exception("No Capture Devices");

			// need to get this from the client settings
			DeviceInformation deviceInfo = captureDeviceCollection[1];
			capture = new Capture(deviceInfo.DriverGuid);

			WaveFormat waveFormat = FormatManager.GetFormat();
			CaptureBufferDescription bufferDescription = new CaptureBufferDescription();
			bufferDescription.BufferBytes = waveFormat.AverageBytesPerSecond;
			bufferDescription.Format = waveFormat;
			_bufferSize = bufferDescription.BufferBytes;
			_bufferDescription = bufferDescription;
			_buffer = new CaptureBuffer(bufferDescription, capture);

			Notify n = new Notify(_buffer);
			BufferPositionNotify[] bpns = new BufferPositionNotify[2];

			// midway notification
			bpns[0] = new BufferPositionNotify();
			bpns[0].Offset = _bufferSize / 2;
			bpns[0].EventNotifyHandle = BufferNotification.SafeWaitHandle.DangerousGetHandle();

			// end notification
			bpns[1] = new BufferPositionNotify();
			bpns[1].Offset = _bufferSize - 1;
			bpns[1].EventNotifyHandle = BufferNotification.SafeWaitHandle.DangerousGetHandle();

			n.SetNotificationPositions(bpns);

			_buffer.Start(true);
		}

		private void ManageBuffer()
		{
			while (Continue)
			{
				// wait for a notification from direct sound
				BufferNotification.WaitOne();

				_buffer.GetCurrentPosition(out CapturePosition, out ReadPosition);

				if (CapturePosition > HalfBufferSize)
				{
					// recording in the second half of the buffer
					_buffer.Read(0, RecordStream, HalfBufferSize, LockFlag.None);
				}
				else
				{
					// recording to front half of buffer
					_buffer.Read(HalfBufferSize, RecordStream, HalfBufferSize, LockFlag.None);
				}

				// bubble up content to client gui
				// RecordBuffer = DigitalSignalProcessor.CleanseA(RecordBuffer);

				ContentNotification(RecordStream.GetBuffer());
				// reset stream position
				RecordStream.Position = 0;
			}
		}

	}


}
